import { uctoo_user,wechatopen_users } from '../../../prisma/generated/uctoo';
import { createSession } from '../services/uctoo/session';
import { v4 as uuidv4 } from 'uuid';
import {
  Request,
  Response,
  DefaultRequestLocals,
  DefaultResponseLocals,
} from 'hyper-express';
import { signJwt } from './jwt';
import { cookieOptions, refreshCookieOptions } from './cookie';
import { AuthProvider, findOrCreateUser, isEmailFree } from '../services/uctoo/uctoo_user';
import db from '../lib/db';
import log from './logger';
import { validateSignUp } from './dataValidation';
import * as bcrypt from 'bcryptjs';
import { connectUserHasGroup } from '../services/uctoo/user_has_group';
import { connectUserHasAccount } from '../services/uctoo/user_has_account';
import { webSocketStore, WebSocketMessage } from '../websocket/websocket-store';

const env = process.env.NODE_ENV;

const isProduction = env === 'production';

//Helper function for getting and setting user tokens
//Helper function for getting and setting user tokens
export async function authorizeAndEnd(
  user: uctoo_user,
  req: Request<DefaultRequestLocals>,
  res: Response<DefaultResponseLocals>,
  authProvider: AuthProvider,
  isLocal?: boolean
) {
  //Create new session
  const session = await createSession(
    user.id,
    req.get('user-agent') || 'No agent detected',
    req.ip,
    authProvider
  );

  //Create access & refresh tokens

  const access_token = signJwt(
    { user: user.id, session: session.id },
    { expiresIn: Number(process.env.ACCESS_TOKEN_VALIDITY_SEC) }
  );

  // Update user model with access_token
  const updatedUser = await db.uctoo_user.update({
    where: { id: user.id },
      data: { access_token: access_token, last_login_time: new Date() }
  });

  const refresh_token = signJwt(
    { user: user.id, session: session.id },
    { expiresIn: '1y' }
  );

  //Set user cookies
  res.cookie('access_token', access_token, 365 * 24 * 60 * 60, cookieOptions);

  res.cookie(
    'refresh_token',
    refresh_token,
    365 * 24 * 60 * 60,
    refreshCookieOptions
  );

  //Redirect to webapp if not credential authorization.
  if (!isLocal)
    return res
      .status(302)
      .redirect(
        isProduction ? process.env.FRONTEND_URL : 'http://localhost:4200/'
      );

  //Or if local just end
  // 去掉password键，返回
  delete updatedUser['password'];
  const resData = {access_token:access_token, refresh_token:refresh_token,user:updatedUser};
  return res.status(200).json(resData);
}

//Helper function for getting and setting user tokens
//Helper function for getting and setting user tokens
export async function authorizeWechatuserAndEnd(
  user: wechatopen_users,
  req: Request<DefaultRequestLocals>,
  res: Response<DefaultResponseLocals>,
  authProvider: AuthProvider,
  state?: string,
  isLocal?: boolean
) {
  if(state){  //微信扫码授权登录
    const removePrefix = (str: string): string => {
      const prefix = 'login_client_id_';
      return str.startsWith(prefix) ? str.slice(prefix.length) : str;
    };
    const client_id = removePrefix(state);

    //通过用户wechatopen_users表的帐号查询是否有关联用户
    let hasUser = await db.user_has_account.findFirst({
      where: {
        account_id: user.id
      }
    });
    if(!hasUser){ //没有用户，注册一个关联用户
      log.info('newUser');
      const lUser = {
        name:user.openid,
        username:user.openid,
        email: user.openid + "@uctoo.com",
        password: "",
        repeat_password: "",
      };
      
      log.info(lUser);
      const isUserValidated = await validateSignUp(lUser);
      log.info('isUserValidated');
      log.info(isUserValidated);
      if (!isUserValidated) { 
        return res.status(400).json({ err: 'isUserValidated', desc: '注册信息验证错误，请检查用户名、邮箱格式，密码需包含大小写字母且8位以上' })
      };
      log.info('!UserValidated');
      log.info(!isUserValidated);
      const isEmailRegistered = await isEmailFree(lUser.email);
      log.info('isEmailRegistered');
      log.info(isEmailRegistered);
      if (!isEmailRegistered)
        return res.status(403).json({ err: 'isUserValidated', desc: '注册邮箱已存在' });
  
      await bcrypt.hash(user.openid, 10).then((hash) => {
        lUser.password = hash;
      });
      log.info('lUser');
      log.info(lUser);
      const newUser = await findOrCreateUser(lUser, AuthProvider.Wechat);
      //新用户加入注册用户组
      const userGroupFromDb = await db.user_group.findFirst({
        where: {
          code: "login",
        },
      });
      const uctooUserHasGroup = {groupable_type:"uctoo_user", status : 1, creator:newUser.id, group_id:userGroupFromDb.id , groupable_id: newUser.id};
      const createdUserHasGroup = await connectUserHasGroup(uctooUserHasGroup);
      if (!createdUserHasGroup) { 
        return res.status(500).json({ err: 'createdUserHasGroup error', desc: '注册用户加入组错误' });
      }

        //user_has_account表添加关联
        const uctooUserHasAccount = {account_type:"wechatopen_users", status : 1, creator:newUser.id, account_id:user.id , user_id: newUser.id};
        const createdUserHasAccount = await connectUserHasAccount(uctooUserHasAccount);
        if (!createdUserHasAccount) { 
          return res.status(500).json({ err: 'createdUserHasAccount error', desc: '注册用户关联帐号错误' });
        }
      
        //Create new session
    const session = await createSession(
      newUser.id,
      req.get('user-agent') || 'No agent detected',
      req.ip,
      authProvider
    );

    //Create access & refresh tokens

    const access_token = signJwt(
      { user: newUser.id, session: session.id },
      { expiresIn: Number(process.env.ACCESS_TOKEN_VALIDITY_SEC) }
    );

    const refresh_token = signJwt(
      { user: newUser.id, session: session.id },
      { expiresIn: '1y' }
    );

    delete newUser['password'];
    const resData = {access_token:access_token, refresh_token:refresh_token, user:newUser};
    //websocket 通知客户端登录结果
    // 获取目标客户端连接
    const client = webSocketStore.getClient(client_id);
    if (!client) {
      return 
    }
    const message: WebSocketMessage = {
      type: 'system',
      content: JSON.stringify(resData),
      timestamp: Date.now(),
      clientId: client_id
    }
    client.send(JSON.stringify(message));

    log.info(resData);
    return res.status(200).json(resData);

    }else{
      const uctooUser =  await db.uctoo_user.findUnique({
        where: {
          id: hasUser.user_id
        }
      });


      //Create new session
    const session = await createSession(
      uctooUser.id,
      req.get('user-agent') || 'No agent detected',
      req.ip,
      authProvider
    );
//Create access & refresh tokens

    const access_token = signJwt(
      { user: uctooUser.id, session: session.id },
      { expiresIn: Number(process.env.ACCESS_TOKEN_VALIDITY_SEC) }
    );

    const refresh_token = signJwt(
      { user: uctooUser.id, session: session.id },
      { expiresIn: '1y' }
    );

    delete uctooUser['password'];
    const resData = {access_token:access_token, refresh_token:refresh_token, user:uctooUser};
    //websocket 通知客户端登录结果
    // 获取目标客户端连接
    const client = webSocketStore.getClient(client_id);
    if (!client) {
      return 
    }
    const message: WebSocketMessage = {
      type: 'system',
      content: JSON.stringify(resData),
      timestamp: Date.now(),
      clientId: client_id
    }
      client.send(JSON.stringify(message));

    log.info(resData);
    return res.status(200).json(resData);

    }

  }else{
    //Create new session
    const session = await createSession(
      user.id,
      req.get('user-agent') || 'No agent detected',
      req.ip,
      authProvider
    );

    //Create access & refresh tokens

    const access_token = signJwt(
      { user: user.id, session: session.id },
      { expiresIn: '120m' }
    );

    const refresh_token = signJwt(
      { user: user.id, session: session.id },
      { expiresIn: '1y' }
    );

    // delete user['password'];
    const resData = {access_token:access_token, refresh_token:refresh_token,user:user};
    return res.status(200).json(resData);
  }
  
}